#include "gtkcssprovider.h"
#include "gtkstylecontextprivate.h"
-/* When checking for changes via the tree we need to know if a rule further
- down the tree matched, because if so we need to add "our bit" to the
- Change. For instance in a a match like *.class:active we'll
- get a tree that first checks :active, if that matches we continue down
- to the tree, and if we get a match we add CHANGE_CLASS. However, the
- end of the tree where we have a match is an ANY which doesn't actually
- modify the change, so we don't know if we have a match or not. We fix
- this by setting GTK_CSS_CHANGE_GOT_MATCH which lets us guarantee
- that change != 0 on any match. */
-#define GTK_CSS_CHANGE_GOT_MATCH GTK_CSS_CHANGE_RESERVED_BIT
-
typedef struct _GtkCssSelectorClass GtkCssSelectorClass;
typedef gboolean (* GtkCssSelectorForeachFunc) (const GtkCssSelector *selector,
const GtkCssMatcher *matcher,
const GtkCssMatcher *matcher);
GtkCssChange (* get_change) (const GtkCssSelector *selector,
GtkCssChange previous_change);
- GtkCssChange (* tree_get_change) (const GtkCssSelectorTree *tree,
- const GtkCssMatcher *matcher);
void (* add_specificity) (const GtkCssSelector *selector,
guint *ids,
guint *classes,
}
}
-static GtkCssChange
-gtk_css_selector_tree_get_change (const GtkCssSelectorTree *tree,
- const GtkCssMatcher *matcher)
-{
- if (tree == NULL)
- return 0;
-
- return tree->selector.class->tree_get_change (tree, matcher);
-}
-
static gboolean
gtk_css_selector_match (const GtkCssSelector *selector,
const GtkCssMatcher *matcher)
return gtk_css_selector_tree_at_offset (tree, tree->sibling_offset);
}
-static GtkCssChange
-gtk_css_selector_tree_get_previous_change (const GtkCssSelectorTree *tree,
- const GtkCssMatcher *matcher)
-{
- GtkCssChange previous_change = 0;
- const GtkCssSelectorTree *prev;
-
- for (prev = gtk_css_selector_tree_get_previous (tree);
- prev != NULL;
- prev = gtk_css_selector_tree_get_sibling (prev))
- previous_change |= gtk_css_selector_tree_get_change (prev, matcher);
-
- return previous_change;
-}
-
/* DEFAULTS */
static void
return FALSE;
}
-static GtkCssChange
-gtk_css_selector_descendant_tree_get_change (const GtkCssSelectorTree *tree,
- const GtkCssMatcher *matcher)
-{
- GtkCssMatcher ancestor;
- GtkCssChange change, previous_change;
-
- change = 0;
- previous_change = 0;
- while (_gtk_css_matcher_get_parent (&ancestor, matcher))
- {
- matcher = &ancestor;
-
- previous_change |= gtk_css_selector_tree_get_previous_change (tree, matcher);
-
- /* any matchers are dangerous here, as we may loop forever, but
- we can terminate now as all possible matches have already been added */
- if (_gtk_css_matcher_matches_any (matcher))
- break;
- }
-
- if (previous_change != 0)
- change |= _gtk_css_change_for_child (previous_change) | GTK_CSS_CHANGE_GOT_MATCH;
-
- return change;
-}
-
static GtkCssChange
gtk_css_selector_descendant_get_change (const GtkCssSelector *selector, GtkCssChange previous_change)
{
gtk_css_selector_descendant_foreach_matcher,
gtk_css_selector_default_match_one,
gtk_css_selector_descendant_get_change,
- gtk_css_selector_descendant_tree_get_change,
gtk_css_selector_default_add_specificity,
gtk_css_selector_default_hash_one,
gtk_css_selector_default_compare_one,
return FALSE;
}
-static GtkCssChange
-gtk_css_selector_descendant_for_region_tree_get_change (const GtkCssSelectorTree *tree,
- const GtkCssMatcher *matcher)
-{
- GtkCssMatcher ancestor;
- GtkCssChange change, previous_change;
-
- previous_change = gtk_css_selector_tree_get_previous_change (tree, matcher);
-
- change = 0;
-
- while (_gtk_css_matcher_get_parent (&ancestor, matcher))
- {
- matcher = &ancestor;
-
- previous_change |= _gtk_css_change_for_child (gtk_css_selector_tree_get_previous_change (tree, matcher));
-
- /* any matchers are dangerous here, as we may loop forever, but
- we can terminate now as all possible matches have already been added */
- if (_gtk_css_matcher_matches_any (matcher))
- break;
- }
-
- if (previous_change != 0)
- change |= previous_change | GTK_CSS_CHANGE_GOT_MATCH;
-
- return change;
-}
-
static GtkCssChange
gtk_css_selector_descendant_for_region_get_change (const GtkCssSelector *selector, GtkCssChange previous_change)
{
gtk_css_selector_descendant_for_region_foreach_matcher,
gtk_css_selector_default_match_one,
gtk_css_selector_descendant_for_region_get_change,
- gtk_css_selector_descendant_for_region_tree_get_change,
gtk_css_selector_default_add_specificity,
gtk_css_selector_default_hash_one,
gtk_css_selector_default_compare_one,
return func (selector, &parent, data);
}
-static GtkCssChange
-gtk_css_selector_child_tree_get_change (const GtkCssSelectorTree *tree,
- const GtkCssMatcher *matcher)
-{
- GtkCssMatcher parent;
- GtkCssChange change, previous_change;
-
- if (!_gtk_css_matcher_get_parent (&parent, matcher))
- return 0;
-
- change = 0;
-
- previous_change = gtk_css_selector_tree_get_previous_change (tree, &parent);
-
- if (previous_change != 0)
- change |= _gtk_css_change_for_child (previous_change) | GTK_CSS_CHANGE_GOT_MATCH;
-
- return change;
-}
-
static GtkCssChange
gtk_css_selector_child_get_change (const GtkCssSelector *selector, GtkCssChange previous_change)
{
gtk_css_selector_child_foreach_matcher,
gtk_css_selector_default_match_one,
gtk_css_selector_child_get_change,
- gtk_css_selector_child_tree_get_change,
gtk_css_selector_default_add_specificity,
gtk_css_selector_default_hash_one,
gtk_css_selector_default_compare_one,
return FALSE;
}
-static GtkCssChange
-gtk_css_selector_sibling_tree_get_change (const GtkCssSelectorTree *tree,
- const GtkCssMatcher *matcher)
-{
- GtkCssMatcher previous;
- GtkCssChange change, previous_change;
-
- change = 0;
-
- previous_change = 0;
- while (_gtk_css_matcher_get_previous (&previous, matcher))
- {
- matcher = &previous;
-
- previous_change |= gtk_css_selector_tree_get_previous_change (tree, matcher);
-
- /* any matchers are dangerous here, as we may loop forever, but
- we can terminate now as all possible matches have already been added */
- if (_gtk_css_matcher_matches_any (matcher))
- break;
- }
-
- if (previous_change != 0)
- change |= _gtk_css_change_for_sibling (previous_change) | GTK_CSS_CHANGE_GOT_MATCH;
-
- return change;
-}
-
static GtkCssChange
gtk_css_selector_sibling_get_change (const GtkCssSelector *selector, GtkCssChange previous_change)
{
gtk_css_selector_sibling_foreach_matcher,
gtk_css_selector_default_match_one,
gtk_css_selector_sibling_get_change,
- gtk_css_selector_sibling_tree_get_change,
gtk_css_selector_default_add_specificity,
gtk_css_selector_default_hash_one,
gtk_css_selector_default_compare_one,
return func (selector, &previous, data);
}
-static GtkCssChange
-gtk_css_selector_adjacent_tree_get_change (const GtkCssSelectorTree *tree,
- const GtkCssMatcher *matcher)
-{
- GtkCssMatcher previous;
- GtkCssChange change, previous_change;
-
- if (!_gtk_css_matcher_get_previous (&previous, matcher))
- return 0;
-
- change = 0;
-
- previous_change = gtk_css_selector_tree_get_previous_change (tree, &previous);
-
- if (previous_change != 0)
- change |= _gtk_css_change_for_sibling (previous_change) | GTK_CSS_CHANGE_GOT_MATCH;
-
- return change;
-}
-
static GtkCssChange
gtk_css_selector_adjacent_get_change (const GtkCssSelector *selector, GtkCssChange previous_change)
{
gtk_css_selector_adjacent_foreach_matcher,
gtk_css_selector_default_match_one,
gtk_css_selector_adjacent_get_change,
- gtk_css_selector_adjacent_tree_get_change,
gtk_css_selector_default_add_specificity,
gtk_css_selector_default_hash_one,
gtk_css_selector_default_compare_one,
} \
\
static GtkCssChange \
-gtk_css_selector_ ## n ##_tree_get_change (const GtkCssSelectorTree *tree, \
- const GtkCssMatcher *matcher) \
-{ \
- GtkCssChange change, previous_change; \
-\
- if (!match_func (&tree->selector, matcher)) \
- return 0; \
-\
- change = 0; \
-\
- if (tree->matches_offset != GTK_CSS_SELECTOR_TREE_EMPTY_OFFSET) \
- change |= GTK_CSS_CHANGE_ ## c | GTK_CSS_CHANGE_GOT_MATCH; \
-\
- previous_change = gtk_css_selector_tree_get_previous_change (tree, matcher); \
-\
- if (previous_change) \
- change |= previous_change | GTK_CSS_CHANGE_ ## c | GTK_CSS_CHANGE_GOT_MATCH; \
-\
- return change; \
-} \
-\
-static GtkCssChange \
gtk_css_selector_ ## n ## _get_change (const GtkCssSelector *selector, GtkCssChange previous_change) \
{ \
return previous_change | GTK_CSS_CHANGE_ ## c; \
gtk_css_selector_default_foreach_matcher, \
match_func, \
gtk_css_selector_ ## n ## _get_change, \
- gtk_css_selector_ ## n ## _tree_get_change, \
gtk_css_selector_ ## n ## _add_specificity, \
hash_func, \
comp_func, \
gtk_css_selector_default_foreach_matcher, \
gtk_css_selector_not_ ## n ## _match_one, \
gtk_css_selector_ ## n ## _get_change, \
- gtk_css_selector_ ## n ## _tree_get_change, \
gtk_css_selector_ ## n ## _add_specificity, \
hash_func, \
comp_func, \
return _gtk_css_matcher_has_region (matcher, selector->region.name, selector->region.flags);
}
-static GtkCssChange
-gtk_css_selector_region_tree_get_change (const GtkCssSelectorTree *tree,
- const GtkCssMatcher *matcher)
-{
- GtkCssChange change, previous_change;
-
- if (!_gtk_css_matcher_has_region (matcher, tree->selector.region.name, tree->selector.region.flags))
- return 0;
-
- change = 0;
-
- if (tree->matches_offset != GTK_CSS_SELECTOR_TREE_EMPTY_OFFSET)
- change |= GTK_CSS_CHANGE_REGION | GTK_CSS_CHANGE_GOT_MATCH;
-
- previous_change = gtk_css_selector_tree_get_previous_change (tree, matcher);
-
- if (previous_change != 0)
- change |= previous_change | GTK_CSS_CHANGE_REGION | GTK_CSS_CHANGE_GOT_MATCH;
-
- return change;
-}
-
static GtkCssChange
gtk_css_selector_region_get_change (const GtkCssSelector *selector, GtkCssChange previous_change)
{
gtk_css_selector_default_foreach_matcher,
gtk_css_selector_region_match_one,
gtk_css_selector_region_get_change,
- gtk_css_selector_region_tree_get_change,
gtk_css_selector_region_add_specificity,
gtk_css_selector_region_hash_one,
gtk_css_selector_region_compare_one,
return array;
}
+static GtkCssChange
+gtk_css_selector_tree_collect_change (const GtkCssSelectorTree *tree)
+{
+ GtkCssChange change = 0;
+ const GtkCssSelectorTree *prev;
+
+ for (prev = gtk_css_selector_tree_get_previous (tree);
+ prev != NULL;
+ prev = gtk_css_selector_tree_get_sibling (prev))
+ change |= gtk_css_selector_tree_collect_change (prev);
+
+ change = tree->selector.class->get_change (&tree->selector, change);
+
+ return change;
+}
+
+static GtkCssChange
+gtk_css_selector_tree_get_change (const GtkCssSelectorTree *tree,
+ const GtkCssMatcher *matcher)
+{
+ GtkCssChange change = 0;
+ const GtkCssSelectorTree *prev;
+
+ if (!gtk_css_selector_match (&tree->selector, matcher))
+ return 0;
+
+ if (tree->selector.class->is_simple)
+ return gtk_css_selector_tree_collect_change (tree);
+
+ for (prev = gtk_css_selector_tree_get_previous (tree);
+ prev != NULL;
+ prev = gtk_css_selector_tree_get_sibling (prev))
+ change |= gtk_css_selector_tree_get_change (prev, matcher);
+
+ change = tree->selector.class->get_change (&tree->selector, change);
+
+ return change;
+}
+
GtkCssChange
_gtk_css_selector_tree_get_change_all (const GtkCssSelectorTree *tree,
const GtkCssMatcher *matcher)
change = 0;
+ /* no need to foreach here because we abort for non-simple selectors */
for (; tree != NULL;
tree = gtk_css_selector_tree_get_sibling (tree))
change |= gtk_css_selector_tree_get_change (tree, matcher);
/* Never return reserved bit set */
- return change & ~GTK_CSS_CHANGE_RESERVED_BIT;
+ return change;
}
#ifdef PRINT_TREE